////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxchi.cpp
/// @brief Landing methods for CamX implementation of CHI
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/// @todo (CAMX-2491) Avoid having in here
#include <system/camera_metadata.h>
#include "camera_metadata_hidden.h"

#include "camxchi.h"
#include "camxchitypes.h"
#include "camxchicontext.h"
#include "camxdebug.h"
#include "camxhal3metadatautil.h"
#include "camxncsservice.h"
#include "camxosutils.h"
#include "camxpipeline.h"
#include "camxtrace.h"
#include "camxutils.h"
#include "camxvendortags.h"

CAMX_NAMESPACE_BEGIN

static ChiContext* g_pChiContext = NULL;

#define CHI_API_MAJOR_VERSION   1
#define CHI_API_MINOR_VERSION   0

/// @todo (CAMX-1223) Remove below and set the vendor tag ops in hal3test/Chinativetest
// Global vendor tag ops
vendor_tag_ops_t g_vendorTagOps;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// GetChiContext
///
/// @brief  Extract the CHI device pointer from the camera3_device_t.
///         Precondition: pCamera3DeviceAPI has been checked for NULL
///
/// @param  pCamera3DeviceAPI The camera3_device_t pointer passed in from the application framework. Assumed that it has been
///                           checked against NULL.
///
/// @return A pointer to the CHIDevice object held in the opaque point in camera3_device_t.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CAMX_INLINE ChiContext* GetChiContext(
    CHIHANDLE hChiContext)
{
    CAMX_ASSERT(NULL != hChiContext);

    return reinterpret_cast<ChiContext*>(hChiContext);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// GetChiSession
///
/// @brief  Get the CHI session pointer
///
/// @param  session session handle
///
/// @return A pointer to the CHISession object held in the opaque point in camera3_device_t.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CAMX_INLINE CHISession* GetChiSession(
    CHIHANDLE hSession)
{
    CAMX_ASSERT(NULL != hSession);

    return reinterpret_cast<CHISession*>(hSession);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// GetChiPipelineDescriptor
///
/// @brief  Get the CHI Pipeline pointer
///
/// @param  hPipelineDescriptor Pipeline pointer
///
/// @return A pointer to the GetChiPipeline object held in the opaque point in camera3_device_t.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CAMX_INLINE PipelineDescriptor* GetChiPipelineDescriptor(
    CHIPIPELINEHANDLE hPipelineDescriptor)
{
    CAMX_ASSERT(NULL != hPipelineDescriptor);

    return reinterpret_cast<PipelineDescriptor*>(hPipelineDescriptor);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiGetTagCount
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CAMX_INLINE INT ChiGetTagCount(
    const vendor_tag_ops_t* pVendorTagOpsAPI)
{
    CAMX_ENTRYEXIT_SCOPE(CamxLogGroupHAL, SCOPEEventHAL3GetTagCount);

    // Per Google, this parameter is extraneous
    CAMX_UNREFERENCED_PARAM(pVendorTagOpsAPI);

    return static_cast<INT>(VendorTagManager::GetTagCount(TagSectionVisibility::TagSectionVisibleToFramework));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiGetAllTags
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void CAMX_INLINE ChiGetAllTags(
    const vendor_tag_ops_t* pVendorTagOpsAPI,
    uint32_t*               pTagArrayAPI)
{
    CAMX_ENTRYEXIT_SCOPE(CamxLogGroupHAL, SCOPEEventHAL3GetAllTags);

    // Per Google, this parameter is extraneous
    CAMX_UNREFERENCED_PARAM(pVendorTagOpsAPI);

    CAMX_STATIC_ASSERT(sizeof(pTagArrayAPI[0]) == sizeof(VendorTag));

    CAMX_ASSERT(NULL != pTagArrayAPI);
    if (NULL != pTagArrayAPI)
    {
        VendorTag* pVendorTags = static_cast<VendorTag*>(pTagArrayAPI);
        VendorTagManager::GetAllTags(pVendorTags, TagSectionVisibility::TagSectionVisibleToFramework);
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Invalid argument 2 for get_all_tags()");
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiGetSectionName
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const CHAR* ChiGetSectionName(
    const vendor_tag_ops_t* pVendorTagOpsAPI,
    uint32_t                tagAPI)
{
    CAMX_ENTRYEXIT_SCOPE(CamxLogGroupHAL, SCOPEEventHAL3GetSectionName);

    // Per Google, this parameter is extraneous
    CAMX_UNREFERENCED_PARAM(pVendorTagOpsAPI);

    CAMX_STATIC_ASSERT(sizeof(tagAPI) == sizeof(VendorTag));

    return VendorTagManager::GetSectionName(static_cast<VendorTag>(tagAPI));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiGetTagName
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const CHAR* ChiGetTagName(
    const vendor_tag_ops_t* pVendorTagOpsAPI,
    uint32_t                tagAPI)
{
    CAMX_ENTRYEXIT_SCOPE(CamxLogGroupHAL, SCOPEEventHAL3GetTagName);

    // Per Google, this parameter is extraneous
    CAMX_UNREFERENCED_PARAM(pVendorTagOpsAPI);

    CAMX_STATIC_ASSERT(sizeof(tagAPI) == sizeof(VendorTag));

    return VendorTagManager::GetTagName(static_cast<VendorTag>(tagAPI));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiGetTagType
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static INT ChiGetTagType(
    const vendor_tag_ops_t* pVendorTagOpsAPI,
    uint32_t                tagAPI)
{
    CAMX_ENTRYEXIT_SCOPE(CamxLogGroupHAL, SCOPEEventHAL3GetTagType);

    // Per Google, this parameter is extraneous
    CAMX_UNREFERENCED_PARAM(pVendorTagOpsAPI);

    CAMX_STATIC_ASSERT(sizeof(tagAPI) == sizeof(VendorTag));

    VendorTagType vendorTagType = VendorTagManager::GetTagType(static_cast<VendorTag>(tagAPI));
    return static_cast<INT>(vendorTagType);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiQueryVendorTagLocation
///
/// @brief  Query vendor tag location assigned by vendor tag manager
///
/// @return CDKResultSuccess if successful otherwise CDKResultNoSuch
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CDKResult ChiQueryVendorTagLocation(
    const CHAR* pSectionName,
    const CHAR* pTagName,
    UINT32*     pTagLocation)
{
    return VendorTagManager::QueryVendorTagLocation(pSectionName, pTagName, pTagLocation);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiSetMetaData
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CDKResult ChiSetMetaData(
    CHIHANDLE handle,
    UINT32    tag,
    VOID*     pData,
    SIZE_T    count)
{
    SIZE_T unit = count / HAL3MetadataUtil::GetSizeByType(HAL3MetadataUtil::GetTypeByTag(tag));
    return HAL3MetadataUtil::SetMetadata(handle, tag, pData, unit);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiGetMetaData
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CDKResult ChiGetMetaData(
    CHIHANDLE handle,
    UINT32    tag,
    VOID*     pData,
    SIZE_T    count)
{
    CDKResult result = CDKResultSuccess;
    VOID* pBuffer;
    result = HAL3MetadataUtil::GetMetadata(handle, tag, &pBuffer);
    if ((NULL != pData) && (NULL != pBuffer))
    {
        Utils::Memcpy(pData, pBuffer, count);
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiGetTagOps
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static VOID ChiGetTagOps(
    CHITAGSOPS* pTagOps)
{
    if (NULL != pTagOps)
    {
        pTagOps->pQueryVendorTagLocation = ChiQueryVendorTagLocation;
        pTagOps->pSetMetaData            = ChiSetMetaData;
        pTagOps->pGetMetaData            = ChiGetMetaData;
    }
}

/*
    创建g_pChiContext，如果支持NCS，则创建NCSService并初始化，最后传递给HwEnvironment
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiOpenContext
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CHIHANDLE ChiOpenContext()
{
    // Non-Camera Service
    NCSService*      pNCSServiceObj   = NULL;
    // 设置返回值
    CamxResult       result           = CamxResultSuccess;
    // 是否启用NCS
    BOOL             isNCSEnabled     = FALSE;

    // 如何g_pChiContext为空，则创建，作用域static文件作用域
    if (NULL == g_pChiContext)
    {
        g_pChiContext = ChiContext::Create();
    }

    // 如果g_pChiContext不为空，则获取HwEnvironment中的设置，根据设置中是否支持NCSService返回bool
    if (NULL != g_pChiContext)
    {
        isNCSEnabled = g_pChiContext->GetStaticSettings()->enableNCSService;
    }

    // 如果支持NCSService
    if (TRUE == isNCSEnabled)
    {
        CAMX_LOG_VERBOSE(CamxLogGroupCore, "NCS Setting Enabled");

        // 如果HwEnvironment中没有NCS对象
        if ((NULL == HwEnvironment::GetInstance()->GetNCSObject()))
        {
            // 实例化NCSService对象
            pNCSServiceObj = CAMX_NEW NCSService();
            // 如果创建成功
            if (NULL != pNCSServiceObj)
            {
                // 初始化NCS线程的数据句柄，创建NCSIntfQSEE对象，若创建成功且传感器可用、能力可用，则将NCSIntfQSEE对象强转为接口类型并传递给NCSService的成员变量m_hNCSServiceContext，并将其初始化
                result = pNCSServiceObj->Initialize(g_pChiContext);
                // 如果初始化成功
                if (CamxResultSuccess == result)
                {
                    // 初始化pNCSServiceObj后赋值给HwEnvironment
                    HwEnvironment::GetInstance()->SetNCSObject(reinterpret_cast<VOID*>(pNCSServiceObj));
                    CAMX_LOG_VERBOSE(CamxLogGroupCore, "Created pNCSServiceObj %p pNCSIntfObject[QSEE] %p",
                                     pNCSServiceObj,
                                     pNCSServiceObj->m_hNCSServiceContext.pNCSIntfObject[QSEE]);
                }
                else
                {
                    CAMX_LOG_ERROR(CamxLogGroupCore, "Unable to initialize NCS Service object!!");
                    CAMX_DELETE pNCSServiceObj;
                    pNCSServiceObj = NULL;
                }
            }
            else
            {
                CAMX_LOG_ERROR(CamxLogGroupCore, "Unable to create NCS Service object, no mem!!");
            }
        }
    }
    else
    {
        CAMX_LOG_VERBOSE(CamxLogGroupCore, "Not creating NCS service handle, NCS disabled");
    }


    return static_cast<CHIHANDLE>(g_pChiContext);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiCloseContext
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static VOID ChiCloseContext(
    CHIHANDLE hChiContext)
{
    NCSService* pNCSServiceObj = NULL;
    BOOL        isNCSEnabled   = FALSE;
    ChiContext* pChiContext    = GetChiContext(hChiContext);

    CAMX_ASSERT(g_pChiContext == pChiContext);

    if (NULL != pChiContext)
    {
        isNCSEnabled = pChiContext->GetStaticSettings()->enableNCSService;

        if (TRUE == isNCSEnabled)
        {
            pNCSServiceObj = reinterpret_cast<NCSService*>(HwEnvironment::GetInstance()->GetNCSObject());
            if (NULL != pNCSServiceObj)
            {
                CAMX_DELETE pNCSServiceObj;
                pNCSServiceObj = NULL;
                HwEnvironment::GetInstance()->SetNCSObject(NULL);
            }
        }
        else
        {
            CAMX_LOG_VERBOSE(CamxLogGroupCore, "NCS Setting Disabled");
        }

        pChiContext->Destroy();
        pChiContext = NULL;
    }


    g_pChiContext = NULL;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiGetNumCameras
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static UINT32 ChiGetNumCameras(
    CHIHANDLE hChiContext)
{
    ChiContext* pChiContext = GetChiContext(hChiContext);
    UINT32      numCameras  = 0;

    numCameras = pChiContext->GetNumCameras();

    return numCameras;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiGetCameraInfo
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CDKResult ChiGetCameraInfo(
    CHIHANDLE      hChiContext,
    UINT32         cameraId,
    CHICAMERAINFO* pChiCameraInfo)
{
    CDKResult   result      = CDKResultSuccess;
    ChiContext* pChiContext = GetChiContext(hChiContext);

    /// @todo (CAMX-2491) CDKResult to CamxResult
    result = pChiContext->GetCameraInfo(cameraId, pChiCameraInfo);

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ChiEnumerateSensorModes
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CDKResult ChiEnumerateSensorModes(
    CHIHANDLE          hChiContext,
    UINT32             cameraId,
    UINT32             numSensorModes,
    CHISENSORMODEINFO* pSensorModeInfo)
{
    CamxResult  result      = CamxResultEFailed;
    ChiContext* pChiContext = NULL;

    CAMX_ASSERT(numSensorModes <= MaxSensorModes);

    if (numSensorModes > MaxSensorModes)
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Unsupported Sensor mode");
        return CamxResultENoSuch;
    }

    if (NULL != hChiContext)
    {
        pChiContext = GetChiContext(hChiContext);

        if (NULL != pChiContext)
        {
            result = pChiContext->EnumerateSensorModes(cameraId, numSensorModes, pSensorModeInfo);
        }
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "hChiContext is NULL");
        result = CamxResultEInvalidArg;
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiCreatePipelineDescriptor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CHIPIPELINEDESCRIPTOR ChiCreatePipelineDescriptor(
    CHIHANDLE                          hChiContext,
    const CHIPIPELINECREATEDESCRIPTOR* pCreateDescriptor,
    UINT32                             numOutputs,
    CHIPORTBUFFERDESCRIPTOR*           pOutputBufferDescriptors,
    UINT32                             numInputs,
    CHIPIPELINEINPUTOPTIONS*           pInputBufferOptions)
{
    CDKResult result = CDKResultSuccess;

    CAMX_ASSERT(NULL != hChiContext);
    CAMX_ASSERT(NULL != pCreateDescriptor);
    CAMX_ASSERT(NULL != pOutputBufferDescriptors);
    CAMX_ASSERT(NULL != pInputBufferOptions);

    ChiNode* pChiNode = &pCreateDescriptor->pNodes[0];

    // Number of input can not be Zero for offline case.
    // Ignore this check for Torch widget node.
    /// @todo (CAMX-3119) remove Torch check below and handle this in generic way.
    if ((NULL != pCreateDescriptor && FALSE == pCreateDescriptor->isRealTime && 0 == numInputs) &&
        ((NULL != pChiNode) && (Torch != pChiNode->nodeId)))
    {
        result = CDKResultEInvalidArg;
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Number of Input cannot be zero for offline use cases!");
    }

    PipelineDescriptor* pPipelineDescriptor = NULL;

    if ((CDKResultSuccess == result)                    &&
        (NULL             != hChiContext)               &&
        (NULL             != pCreateDescriptor)         &&
        (NULL             != pOutputBufferDescriptors)  &&
        (NULL             != pInputBufferOptions))
    {
        ChiContext* pChiContext = GetChiContext(hChiContext);

        pPipelineDescriptor = pChiContext->CreatePipelineDescriptor(pCreateDescriptor,
                                                                    numOutputs,
                                                                    pOutputBufferDescriptors,
                                                                    numInputs,
                                                                    pInputBufferOptions);
    }
    else
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Invalid input parameters!");
    }

    return reinterpret_cast<CHIPIPELINEDESCRIPTOR>(pPipelineDescriptor);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiDestroyPipelineDescriptor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static VOID ChiDestroyPipelineDescriptor(
    CHIHANDLE             hChiContext,
    CHIPIPELINEDESCRIPTOR hPipelineDescriptor)
{
    ChiContext*         pChiContext         = GetChiContext(hChiContext);
    PipelineDescriptor* pPipelineDescriptor = GetChiPipelineDescriptor(hPipelineDescriptor);

    pChiContext->DestroyPipelineDescriptor(pPipelineDescriptor);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiCreateSession
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CHIHANDLE ChiCreateSession(
    CHIHANDLE        hChiContext,
    UINT             numPipelines,
    CHIPIPELINEINFO* pPipelineInfo,
    CHICALLBACKS*    pCallbacks,
    VOID*            pPrivateCallbackData,
    CHISESSIONFLAGS  sessionCreateflags)
{
    CHISession* pCHISession = NULL;

    if ((NULL != hChiContext) && (NULL != pPipelineInfo) && (NULL != pCallbacks))
    {
        ChiContext* pChiContext = GetChiContext(hChiContext);

        pCHISession = pChiContext->CreateSession(numPipelines,
                                                 pPipelineInfo,
                                                 pCallbacks,
                                                 pPrivateCallbackData,
                                                 sessionCreateflags);
    }

    return reinterpret_cast<CHIHANDLE>(pCHISession);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiDestroySession
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static VOID ChiDestroySession(
    CHIHANDLE hChiContext,
    CHIHANDLE hSession,
    BOOL isForced)
{
    ChiContext* pChiContext = GetChiContext(hChiContext);
    CHISession* pCHISession = GetChiSession(hSession);

    pChiContext->DestroySession(pCHISession, isForced);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiFlushSession
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static VOID ChiFlushSession(
    CHIHANDLE hChiContext,
    CHIHANDLE hSession,
    BOOL isForced)
{
    ChiContext* pChiContext = GetChiContext(hChiContext);
    CHISession* pCHISession = GetChiSession(hSession);

    pChiContext->FlushSession(pCHISession, isForced);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiActivatePipeline
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CDKResult ChiActivatePipeline(
    CHIHANDLE          hChiContext,
    CHIHANDLE          hSession,
    CHIHANDLE          hPipeline,
    CHISENSORMODEINFO* pModeInfo)
{
    CDKResult           result              = CDKResultSuccess;
    ChiContext*         pChiContext         = GetChiContext(hChiContext);
    CHISession*         pChiSession         = GetChiSession(hSession);
    CHIPIPELINEHANDLE   hPipelineDescriptor = hPipeline;

    CAMX_UNREFERENCED_PARAM(pModeInfo);
    
    // 激活管道
    result = pChiContext->ActivatePipeline(pChiSession, hPipelineDescriptor);

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiDeactivatePipeline
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CDKResult ChiDeactivatePipeline(
    CHIHANDLE                   hChiContext,
    CHIHANDLE                   hSession,
    CHIHANDLE                   hPipeline,
    CHIDEACTIVATEPIPELINEMODE   modeBitmask)
{
    CDKResult           result              = CDKResultSuccess;
    ChiContext*         pChiContext         = GetChiContext(hChiContext);
    CHISession*         pChiSession         = GetChiSession(hSession);
    CHIPIPELINEHANDLE   hPipelineDescriptor = hPipeline;

    result = pChiContext->DeactivatePipeline(pChiSession, hPipelineDescriptor, modeBitmask);

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiSubmitPipelineRequest
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static CDKResult ChiSubmitPipelineRequest(
    CHIHANDLE           hChiContext,
    CHIPIPELINEREQUEST* pRequest)
{
    CDKResult   result      = CDKResultSuccess;
    ChiContext* pChiContext = GetChiContext(hChiContext);
    CHISession* pCHISession = GetChiSession(pRequest->pSessionHandle);

    result = pChiContext->SubmitRequest(pCHISession, pRequest);

    if (CDKResultSuccess != result)
    {
        CAMX_LOG_ERROR(CamxLogGroupHAL, "Submit request failed with error %d.", result);
    }

    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiOverrideBypass
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID ChiOverrideBypass(
    HALCallbacks* pBypassCallbacks)
{
    CAMX_UNREFERENCED_PARAM(pBypassCallbacks);
}

CAMX_NAMESPACE_END

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiEntry
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CAMX_VISIBILITY_PUBLIC VOID ChiEntry(
    ChiContextOps* pChiContextOps)
{
    if (NULL != pChiContextOps)
    {
        pChiContextOps->size                       = sizeof(ChiContextOps);

        pChiContextOps->majorVersion               = CHI_API_MAJOR_VERSION;
        pChiContextOps->minorVersion               = CHI_API_MINOR_VERSION;
        pChiContextOps->pOpenContext               = CamX::ChiOpenContext;
        pChiContextOps->pCloseContext              = CamX::ChiCloseContext;
        pChiContextOps->pGetNumCameras             = CamX::ChiGetNumCameras;
        pChiContextOps->pGetCameraInfo             = CamX::ChiGetCameraInfo;
        pChiContextOps->pEnumerateSensorModes      = CamX::ChiEnumerateSensorModes;
        pChiContextOps->pCreatePipelineDescriptor  = CamX::ChiCreatePipelineDescriptor;
        pChiContextOps->pDestroyPipelineDescriptor = CamX::ChiDestroyPipelineDescriptor;
        pChiContextOps->pCreateSession             = CamX::ChiCreateSession;
        pChiContextOps->pDestroySession            = CamX::ChiDestroySession;
        pChiContextOps->pFlushSession              = CamX::ChiFlushSession;
        pChiContextOps->pActivatePipeline          = CamX::ChiActivatePipeline;
        pChiContextOps->pDeactivatePipeline        = CamX::ChiDeactivatePipeline;
        pChiContextOps->pSubmitPipelineRequest     = CamX::ChiSubmitPipelineRequest;
        pChiContextOps->pTagOps                    = CamX::ChiGetTagOps;
    }

    // This is the workaround for presil HAL3test on Windows
    // On Device, set_camera_metadata_vendor_ops will be call the set the
    // static vendor tag operation in camera_metadata.c
    //
    // On Windows side, theoretically hal3test should mimic what Android framework
    // does and call the set_camera_metadata_vendor_ops function in libcamxext library
    // However, in Windows, if both hal3test.exe and hal.dll link to libcamxext library,
    // there are two different instance of static varibles sit in different memory location.
    // Even if set_camera_metadata_vendor_ops is called in hal3test, when hal try to
    // access to vendor tag ops, it is still not set.
    //
    // This is also a workaround to call vendor tag ops in Chi at GetNumCameras which happens to get called before
    // GetVendorTagOps
    CamX::g_vendorTagOps.get_all_tags     = CamX::ChiGetAllTags;
    CamX::g_vendorTagOps.get_section_name = CamX::ChiGetSectionName;
    CamX::g_vendorTagOps.get_tag_count    = CamX::ChiGetTagCount;
    CamX::g_vendorTagOps.get_tag_name     = CamX::ChiGetTagName;
    CamX::g_vendorTagOps.get_tag_type     = CamX::ChiGetTagType;

    set_camera_metadata_vendor_ops(&(CamX::g_vendorTagOps));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ChiDumpState
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID ChiDumpState(
    INT fd)
{
    CamX::g_pChiContext->DumpState(fd);
}
